﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Vowei.Data;
using Vowei.Core.Models;
using Vowei.Web.Controllers;
using System.Web.Mvc;
using Vowei.Data.Models;
using NMock2;
using Autofac;
using Vowei.Web;
using Autofac.Integration.Web;

namespace vowei.test.ModelTest
{
    [TestClass]
    public class HistoryTest : TestBase
    {
        [TestMethod]
        public void AddItemChangeHistoryBasicTest()
        {
            var target = new ProjectController(VoweiContext, Setting.DefaultFormUser);

            var expectedDate = DateTime.Now;
            var project = new Project()
            {
                Title = "ChangeHistoryBasicTest_Project",
                Owner = "yimin_shi@hotmail.com",
                StartDate = expectedDate,
                DueDate = expectedDate + TimeSpan.FromDays(30)
            };
            target.Create(project);

            using (var context = new VoweiContextImpl())
            {
                var histories = from h in context.Comments
                                where h.PostId.CompareTo(project.ID) == 0
                                orderby h.CommentDate
                                select h;

                Assert.AreNotEqual(0, histories.Count());

                var actual = histories.First();
                Assert.AreEqual(expectedDate.Year, actual.CommentDate.Year);
                Assert.AreEqual(expectedDate.Month, actual.CommentDate.Month);
                Assert.AreEqual(expectedDate.Day, actual.CommentDate.Day);
                Assert.AreEqual(expectedDate.Hour, actual.CommentDate.Hour);
                Assert.AreEqual(expectedDate.Minute, actual.CommentDate.Minute);
                Assert.AreEqual(expectedDate.Second, actual.CommentDate.Second);
            }
        }

        [TestMethod]
        public void ChangeItemPropertyHistoryTest()
        {
            var target = new ProjectController(VoweiContext, Setting.DefaultFormUser);

            var expectedDate = DateTime.Now;
            var oldTitle = "ChangeItemPropertyHistoryTest_Project";
            var oldDue = expectedDate + TimeSpan.FromDays(30);
            var project = new Project()
            {
                Title = oldTitle,
                Owner = "yimin_shi@hotmail.com",
                StartDate = expectedDate,
                DueDate = oldDue
            };

            using (var impl = new VoweiContextImpl())
            {
                impl.Projects.Add(project);
                impl.SaveChanges();
            }

            var newTitle = "ChangeItemPropertyHistoryTest_Updated";
            var newDue = project.StartDate + TimeSpan.FromDays(300);;
            project.Title = newTitle;
            project.DueDate = newDue;
            var newDuration = project.DueDate;

            var result = target.Edit(project);
            Assert.IsTrue(result is RedirectToRouteResult);

            using (var context = new VoweiContextImpl())
            {
                var histories = from h in context.Comments
                                where h.PostId.CompareTo(project.ID) == 0
                                orderby h.CommentDate descending
                                select h;

                Assert.AreNotEqual(0, histories.Count());

                var actual = histories.First();
                // 记录了标题的改动
                Assert.IsTrue(actual.Text.IndexOf(oldTitle) >= 0);
                Assert.IsTrue(actual.Text.IndexOf(newTitle) >= 0);
                // 记录了结束日期的改动
                // TODO: 要考虑国际化的因素
                Assert.IsTrue(actual.Text.IndexOf(oldDue.ToString()) >= 0);
                Assert.IsTrue(actual.Text.IndexOf(newDue.ToString()) >= 0);
            }
        }

        [TestMethod]
        public void ChangeCollectionPropertyHistoryTest()
        {
            var project = CreateProjectHelper("ChangeCollectionPropertyHistoryTest");
            project.Children.Add(CreateMilestoneHelper("ChangeCollectionPropertyHistoryTest"));
            project.Children.ElementAt(0).DueDate = project.StartDate + TimeSpan.FromDays(15);
            var milestone = CreateMilestoneHelper("ChangeCollectionPropertyHistoryTest_Another");
            milestone.StartDate = project.Children.ElementAt(0).DueDate;
            milestone.DueDate = project.DueDate;

            using (var context = new VoweiContextImpl())
            {
                context.Projects.Add(project);
                context.Milestones.Add(milestone);
                context.SaveChanges();
            }

            var target = new ProjectController(VoweiContext, Setting.DefaultFormUser);

            // 往项目里添加一个新的里程碑
            project = CloneProjectHelper(project);
            project.Children.Add(new Milestone() { ID = milestone.ID });
            var result = target.Edit(project);

            Assert.IsTrue(result is RedirectToRouteResult);

            using (var context = new VoweiContextImpl())
            {
                project = context.Projects.Include("Comments").First(p => p.ID == project.ID);

                var histories = project.Comments.OrderByDescending(c => c.CommentDate);
                var history = histories.First();

                // 针对集合属性，暂不支持根据集合内部具体的改动
                Assert.IsTrue(history.Text.Contains("子里程碑"));
            }
        }

        [TestMethod]
        public void LastModifiedByBasicTest()
        {
            var project = CreateProjectHelper("LastModifiedByBasicTest");
            var target = new ProjectController(VoweiContext, Setting.DefaultFormUser);
            var result = target.Create(project);

            using (var context = new VoweiContextImpl())
            {
                var histories = from h in context.Comments
                                where h.PostId.CompareTo(project.ID) == 0
                                orderby h.CommentDate descending
                                select h;
                var history = histories.First();
                Assert.AreEqual(Setting.DefaultUserName, history.User);
            }

            var origProvider = MvcApplication.ContainerProviderStatic;
            var expectedUser = "yimin_shi@hotmail.com";
            MvcApplication.ContainerProviderStatic = null;
            var mocks = new Mockery();
            var user = mocks.NewMock<IUser>();
            Expect.AtLeastOnce.On(user).GetProperty("Email").Will(Return.Value(expectedUser));
            var builder = new ContainerBuilder();
            builder.RegisterInstance(user).As<IUser>();

            var container = builder.Build();
            try
            {
                using (var context = new VoweiContextImpl())
                {
                    target = new ProjectController(new VoweiContext(context), Setting.DefaultFormUser);
                    MvcApplication.ContainerProviderStatic = new ContainerProvider(container);
                    project.Title = "LastModifiedByBasicTest_Project_Modified";
                    result = target.Edit(project);
                }

                using (var context = new VoweiContextImpl())
                {
                    var histories = from h in context.Comments
                                    where h.PostId.CompareTo(project.ID) == 0
                                    orderby h.CommentDate descending
                                    select h;
                    var history = histories.First();
                    Assert.AreEqual(expectedUser, history.User);
                    Assert.IsTrue(history.Text.Contains(expectedUser));
                }
            }
            finally
            {
                MvcApplication.ContainerProviderStatic = origProvider;
            }
        }

        [TestMethod]
        public void ChangeItemDoesnotTraceDefaultPropertyChanges()
        {
            var target = new ProjectController(VoweiContext, Setting.DefaultFormUser);

            var project = CreateProjectHelper("ChangeItemDoesnotTraceDefaultPropertyChanges");
            using (var impl = new VoweiContextImpl())
            {
                impl.Projects.Add(project);
                impl.SaveChanges();
            }

            var newTitle = "ChangeItemDoesnotTraceDefaultPropertyChanges_New";
            project.Title = newTitle;

            var result = target.Edit(project);
            Assert.IsTrue(result is RedirectToRouteResult);

            var histories = from h in VoweiContext.Comments.Query
                            where h.PostId.CompareTo(project.ID) == 0
                            orderby h.CommentDate descending
                            select h;

            Assert.AreNotEqual(0, histories.Count());

            var actual = histories.First();
            // 记录了标题的改动
            Assert.IsTrue(actual.Text.IndexOf(newTitle) >= 0);

            Assert.IsFalse(actual.Text.IndexOf("Vowei.Data.Models.Comment") >= 0);
            Assert.IsFalse(actual.Text.IndexOf("最后变更日期") >= 0);
            Assert.IsFalse(actual.Text.IndexOf("创建日期") >= 0);
        }

        [TestMethod]
        public void ChangeDescriptionPropertyTest()
        {
            Requirement requirement = null;
            var expected = "修改过的需求描述文本";
            using (var context = new VoweiContextImpl())
            {
                var project = GetDefaultProject(context);
                requirement = CreateRequirementHelper("ChangeDescriptionPropertyTest", project);

                context.Requirements.Add(requirement);
                context.SaveChanges();
            }

            var controller = new RequirementController(VoweiContext, Setting.DefaultFormUser);
            requirement.Description = expected;
            var result = controller.Edit(requirement) as RedirectToRouteResult;

            Assert.IsNotNull(result);

            using (var context = new VoweiContextImpl())
            {
                var histories = GetHistories(requirement, context);
                Assert.AreEqual(1, histories.Count());

                var actual = histories.First();
                // 记录了描述的改动
                Assert.IsTrue(actual.Text.IndexOf("说明") >= 0);
                Assert.IsTrue(actual.Text.IndexOf(expected) >= 0);
            }
        }
    }
}
